#pragma once

#include "traits.h"

#include <type_traits>
#include <utility>

/**
 * @brief 基于 tag_invoke 的 C++17 序列化/反序列化 CPO（Customization Point Object）基础设施
 *
 * 设计初衷：
 * 1. 提供零成本抽象的统一接口，允许用户以 tag_invoke、ADL
 * 自由函数、成员函数三种方式扩展序列化行为。
 * 2. 在 C++17 下模拟 C++20 的 concept + tag_invoke 机制，保证向后兼容。
 * 3. 通过优先级调度器在编译期自动选择最优实现，优先级：tag_invoke > ADL > 成员/静态成员。
 * 4. 所有检测逻辑均为编译期 constexpr，不占用运行时开销。
 * 5. 使用 delete 声明的占位函数可防止意外 ADL 匹配，同时提供清晰编译期错误信息。
 *
 * 设计要点：
 * - tag_invoke_t：通用转发对象，保证 noexcept 与返回类型精确转发。
 * - serialize_tag_t / deserialize_tag_t<T>：标签类型，用于 tag_invoke 分派，避免命名冲突。
 * - type_tag_t<T>：类型标签，用于在反序列化中显式传递目标类型，避免模板参数推导失败。
 * - detail::*_impl：SFINAE 检测实现，统一使用 void_t 技巧，保证 C++17 兼容性。
 * - serialize_dispatcher_t / deserialize_dispatcher_t：优先级调度器，使用 if constexpr
 * 在编译期展开。
 * - serialize_value_cpo_t / deserialize_value_cpo_t：最终暴露的 CPO 对象，提供唯一入口，支持
 * noexcept 精确传播。
 */
namespace serializer
{

/**
 * @brief tag_invoke 通用转发对象（C++17 兼容）
 *
 * 设计初衷：
 * - 在 C++17 下提供与 C++20 tag_invoke 完全兼容的调用语法。
 * - 通过 noexcept(&&) 与 -> decltype 精确转发，保证异常规格与返回类型不丢失。
 *
 * 用法示例：
 * @code
 *     tag_invoke_fn(my_tag, arg1, arg2);
 * @endcode
 */
struct tag_invoke_t
{
    /**
     * @brief 调用用户自定义的 tag_invoke(tag, args...)
     * @param tag  标签对象，用于分派到具体实现
     * @param args 任意实参，将完美转发
     * @return     用户实现的 tag_invoke 返回值
     * @note       异常规格与返回值完全由用户实现决定
     */
    template <typename Tag, typename... Args>
    constexpr auto operator()(Tag tag, Args &&... args) const
        noexcept(noexcept(tag_invoke(tag, std::forward<Args>(args)...)))
            -> decltype(tag_invoke(tag, std::forward<Args>(args)...))
    {
        return tag_invoke(tag, std::forward<Args>(args)...);
    }
};

/**
 * @brief 全局唯一 tag_invoke 转发实例
 */
inline constexpr tag_invoke_t tag_invoke_fn{};

/**
 * @brief 序列化标签类型
 *
 * 设计初衷：
 * - 作为 tag_invoke 的第一个实参，用于将调用分派到用户自定义的序列化实现。
 * - 空类设计，零开销，仅用于标签分派。
 */
struct serialize_tag_t
{
};

/**
 * @brief 反序列化标签类型（依赖目标类型 T）
 *
 * 设计初衷：
 * - 携带目标类型信息，支持重载 tag_invoke(deserialize_tag<T>, ...)。
 * - 模板化设计，保证不同类型互不冲突。
 *
 * @tparam T 目标类型，用于 tag_invoke 分派与返回值检查
 */
template <typename T>
struct deserialize_tag_t
{
    using type = T; ///< 公开类型别名，方便外部取用
};

/**
 * @brief 序列化标签全局实例
 */
inline constexpr serialize_tag_t serialize_tag{};

/**
 * @brief 反序列化标签全局实例（模板变量）
 * @tparam T 目标类型
 */
template <typename T>
inline constexpr deserialize_tag_t<T> deserialize_tag{};

/**
 * @brief 类型标签辅助工具
 *
 * 设计初衷：
 * - 在反序列化接口中显式传递目标类型，避免模板参数推导失败。
 * - 空类设计，零开销，仅用于类型标记。
 *
 * @tparam T 需要标记的目标类型
 */
template <typename T>
struct type_tag_t
{
    using type = T; ///< 公开类型别名
};

/**
 * @brief 类型标签全局实例（模板变量）
 * @tparam T 目标类型
 */
template <typename T>
inline constexpr type_tag_t<T> type_tag{};

/**
 * @brief ADL 自由函数占位锚点（C++17：声明为删除）
 *
 * 设计初衷：
 * - 阻止未定义实现被意外调用，同时让编译器在 ADL 查找时找到唯一候选。
 * - 删除声明保证链接期错误，配合 static_assert 提供清晰诊断信息。
 *
 * @tparam Writer   Writer 概念类型
 * @tparam T        值类型
 * @tparam Options  选项类型
 */
template <typename Writer, typename T, typename Options>
void serialize_value(Writer &, const T &, const Options &) = delete;

/**
 * @brief ADL 自由函数占位锚点（反序列化版本）
 *
 * @tparam T        目标类型
 * @tparam Reader   Reader 概念类型
 * @tparam Options  选项类型
 */
template <typename T, typename Reader, typename Options>
T deserialize_value(Reader &, const Options &, type_tag_t<T>) = delete;

/**
 * @brief 内部检测工具命名空间
 *
 * 设计初衷：
 * - 集中所有 SFINAE 实现细节，避免污染外部命名空间。
 * - 统一使用 void_t 技巧，保证 C++17 兼容性。
 */
namespace detail
{

/**
 * @brief 检测是否存在 tag_invoke(serialize_tag, writer, value, options)
 *
 * 设计要点：
 * - 使用 void_t 检测表达式是否合法。
 * - 结果保存在 ::value 中，用于后续 if constexpr 分支。
 */
template <typename T, typename Writer, typename Options, typename = void>
struct has_tag_invoke_serialize_impl : std::false_type
{
};

template <typename T, typename Writer, typename Options>
struct has_tag_invoke_serialize_impl<
    T,
    Writer,
    Options,
    ::serializer::detail::void_t<decltype(tag_invoke(serialize_tag,
                                                     std::declval<Writer &>(),
                                                     std::declval<const T &>(),
                                                     std::declval<const Options &>()))>>
    : std::true_type
{
};

/**
 * @brief 检测是否存在 tag_invoke(deserialize_tag<T>, reader, options) 且返回类型可转换为 T
 *
 * 额外约束：
 * - 要求返回类型可转换为 T，防止错误实现被选中。
 */
template <typename T, typename Reader, typename Options, typename = void>
struct has_tag_invoke_deserialize_impl
{
    static constexpr bool value = false;
};

template <typename T, typename Reader, typename Options>
struct has_tag_invoke_deserialize_impl<
    T,
    Reader,
    Options,
    ::serializer::detail::void_t<decltype(tag_invoke(
        deserialize_tag<T>, std::declval<Reader &>(), std::declval<const Options &>()))>>
{
    using R = decltype(tag_invoke(
        deserialize_tag<T>, std::declval<Reader &>(), std::declval<const Options &>()));
    static constexpr bool value = std::is_convertible<R, T>::value;
};

/**
 * @brief 检测是否存在 ADL serialize_value(writer, value, options)
 */
template <typename T, typename Writer, typename Options, typename = void>
struct has_adl_serialize_impl : std::false_type
{
};

template <typename T, typename Writer, typename Options>
struct has_adl_serialize_impl<
    T,
    Writer,
    Options,
    ::serializer::detail::void_t<decltype(serialize_value(
        std::declval<Writer &>(), std::declval<const T &>(), std::declval<const Options &>()))>>
    : std::true_type
{
};

/**
 * @brief 检测是否存在 ADL deserialize_value(reader, options, type_tag<T>) 且返回类型可转换为 T
 */
template <typename T, typename Reader, typename Options, typename = void>
struct has_adl_deserialize_impl
{
    static constexpr bool value = false;
};

template <typename T, typename Reader, typename Options>
struct has_adl_deserialize_impl<
    T,
    Reader,
    Options,
    ::serializer::detail::void_t<decltype(deserialize_value(
        std::declval<Reader &>(), std::declval<const Options &>(), type_tag<T>))>>
{
    using R = decltype(deserialize_value(
        std::declval<Reader &>(), std::declval<const Options &>(), type_tag<T>));
    static constexpr bool value = std::is_convertible<R, T>::value;
};

/**
 * @brief 检测是否存在成员函数 value.serialize(writer, options)
 */
template <typename T, typename Writer, typename Options, typename = void>
struct has_member_serialize_impl : std::false_type
{
};

template <typename T, typename Writer, typename Options>
struct has_member_serialize_impl<
    T,
    Writer,
    Options,
    ::serializer::detail::void_t<decltype(std::declval<const T &>().serialize(
        std::declval<Writer &>(), std::declval<const Options &>()))>> : std::true_type
{
};

/**
 * @brief 检测是否存在静态成员函数 T::deserialize(reader, options) 且返回类型可转换为 T
 */
template <typename T, typename Reader, typename Options, typename = void>
struct has_static_member_deserialize_impl
{
    static constexpr bool value = false;
};

template <typename T, typename Reader, typename Options>
struct has_static_member_deserialize_impl<
    T,
    Reader,
    Options,
    ::serializer::detail::void_t<decltype(T::deserialize(std::declval<Reader &>(),
                                                         std::declval<const Options &>()))>>
{
    using R = decltype(T::deserialize(std::declval<Reader &>(), std::declval<const Options &>()));
    static constexpr bool value = std::is_convertible<R, T>::value;
};

} // namespace detail

/**
 * @brief 变量模板：是否存在 tag_invoke 序列化路径
 * @tparam T       值类型
 * @tparam Writer  Writer 概念类型
 * @tparam Options 选项类型
 */
template <typename T, typename Writer, typename Options>
constexpr bool has_tag_invoke_serialize =
    detail::has_tag_invoke_serialize_impl<T, Writer, Options>::value;

/**
 * @brief 变量模板：是否存在 tag_invoke 反序列化路径
 */
template <typename T, typename Reader, typename Options>
constexpr bool has_tag_invoke_deserialize =
    detail::has_tag_invoke_deserialize_impl<T, Reader, Options>::value;

/**
 * @brief 变量模板：是否存在 ADL 序列化路径
 */
template <typename T, typename Writer, typename Options>
constexpr bool has_adl_serialize = detail::has_adl_serialize_impl<T, Writer, Options>::value;

/**
 * @brief 变量模板：是否存在 ADL 反序列化路径
 */
template <typename T, typename Reader, typename Options>
constexpr bool has_adl_deserialize = detail::has_adl_deserialize_impl<T, Reader, Options>::value;

/**
 * @brief 变量模板：是否存在成员序列化路径
 */
template <typename T, typename Writer, typename Options>
constexpr bool has_member_serialize = detail::has_member_serialize_impl<T, Writer, Options>::value;

/**
 * @brief 变量模板：是否存在静态成员反序列化路径
 */
template <typename T, typename Reader, typename Options>
constexpr bool has_static_member_deserialize =
    detail::has_static_member_deserialize_impl<T, Reader, Options>::value;

/**
 * @brief 序列化优先级调度器（C++17 约束：enable_if）
 *
 * 设计初衷：
 * - 在编译期按优先级选择最优实现，优先级：tag_invoke > ADL > 成员函数。
 * - 若三路均未找到，则 static_assert 给出清晰诊断。
 *
 * 用法示例：
 * @code
 *     serialize_dispatcher(writer, value, options);
 * @endcode
 */
struct serialize_dispatcher_t
{
    /**
     * @brief 执行序列化调度
     * @tparam Writer  满足 writer 概念
     * @tparam T       值类型
     * @tparam Options 满足 serialization_options 概念
     * @param writer   输出器
     * @param value    常量引用，待序列化值
     * @param options  选项对象
     * @note           函数体内使用 if constexpr，保证仅选中路径被实例化
     */
    template <
        typename Writer,
        typename T,
        typename Options,
        typename std::enable_if<writer<Writer> && serialization_options<Options>, int>::type = 0>
    constexpr void operator()(Writer & writer, const T & value, const Options & options) const
    {
        if constexpr (has_tag_invoke_serialize<T, Writer, Options>)
        {
            // 优先级1: tag_invoke
            tag_invoke_fn(serialize_tag, writer, value, options);
        }
        else if constexpr (has_adl_serialize<T, Writer, Options>)
        {
            // 优先级2: ADL
            serialize_value(writer, value, options);
        }
        else if constexpr (has_member_serialize<T, Writer, Options>)
        {
            // 优先级3: 成员函数
            value.serialize(writer, options);
        }
        else
        {
            static_assert(has_tag_invoke_serialize<T, Writer, Options> ||
                              has_adl_serialize<T, Writer, Options> ||
                              has_member_serialize<T, Writer, Options>,
                          "No serialization path found: provide tag_invoke(serialize_tag_t, ...), "
                          "ADL serialize_value, or member function serialize.");
        }
    }
};

/**
 * @brief 反序列化优先级调度器
 *
 * 设计初衷：
 * - 与 serialize_dispatcher_t 对称，优先级：tag_invoke > ADL > 静态成员函数。
 * - 若三路均未找到，则 static_assert 给出清晰诊断；若 T
 * 可默认构造，则额外提供回退路径（注释中保留，实际由 static_assert 阻断）。
 */
struct deserialize_dispatcher_t
{
    /**
     * @brief 执行反序列化调度
     * @tparam T       目标类型
     * @tparam Reader  满足 reader 概念
     * @tparam Options 满足 serialization_options 概念
     * @param reader   输入器
     * @param options  选项对象
     * @param tag      类型标签，仅用于显式选择 T
     * @return         T 类型的反序列化结果
     * @note           函数体内使用 if constexpr，保证仅选中路径被实例化
     */
    template <
        typename T,
        typename Reader,
        typename Options,
        typename std::enable_if<reader<Reader> && serialization_options<Options>, int>::type = 0>
    constexpr T operator()(Reader & reader, const Options & options, type_tag_t<T> tag) const
    {
        (void)tag; // 未使用，仅用于显式选择 T
        if constexpr (has_tag_invoke_deserialize<T, Reader, Options>)
        {
            // 优先级1: tag_invoke
            return tag_invoke_fn(deserialize_tag<T>, reader, options);
        }
        else if constexpr (has_adl_deserialize<T, Reader, Options>)
        {
            // 优先级2: ADL
            return deserialize_value(reader, options, type_tag<T>);
        }
        else if constexpr (has_static_member_deserialize<T, Reader, Options>)
        {
            // 优先级3: 静态成员函数
            return T::deserialize(reader, options);
        }
        else
        {
            static_assert(has_tag_invoke_deserialize<T, Reader, Options> ||
                              has_adl_deserialize<T, Reader, Options> ||
                              has_static_member_deserialize<T, Reader, Options>,
                          "No deserialization path found: provide tag_invoke(deserialize_tag_t<T>, "
                          "...), ADL deserialize_value, or static T::deserialize.");
            // 添加默认返回以满足编译器的返回路径检查；若以上 static_assert 失败，此处不会被编译。
            return T{};
        }
    }
};

/**
 * @brief 全局唯一序列化调度器实例
 */
inline constexpr serialize_dispatcher_t serialize_dispatcher{};

/**
 * @brief 全局唯一反序列化调度器实例
 */
inline constexpr deserialize_dispatcher_t deserialize_dispatcher{};

/**
 * @brief 序列化 CPO 最终接口
 *
 * 设计初衷：
 * - 提供唯一入口，隐藏调度器细节。
 * - 通过 noexcept 精确传播内部异常规格。
 */
struct serialize_value_cpo_t
{
    /**
     * @brief 执行序列化
     * @tparam Writer  满足 writer 概念
     * @tparam T       值类型
     * @tparam Options 满足 serialization_options 概念
     * @param writer   输出器
     * @param value    常量引用，待序列化值
     * @param options  选项对象
     * @note           异常规格与内部调度器完全一致
     */
    template <typename Writer,
              typename T,
              typename Options,
              typename std::enable_if<serialization_options<Options>, int>::type = 0>
    constexpr void operator()(Writer & writer, const T & value, const Options & options) const
        noexcept(noexcept(serialize_dispatcher(writer, value, options)))
    {
        serialize_dispatcher(writer, value, options);
    }
};

/**
 * @brief 反序列化 CPO 最终接口
 */
struct deserialize_value_cpo_t
{
    /**
     * @brief 执行反序列化
     * @tparam T       目标类型
     * @tparam Reader  满足 reader 概念
     * @tparam Options 满足 serialization_options 概念
     * @param reader   输入器
     * @param options  选项对象
     * @param tag      类型标签，默认构造即可
     * @return         T 类型的反序列化结果
     * @note           异常规格与内部调度器完全一致
     */
    template <typename T,
              typename Reader,
              typename Options,
              typename std::enable_if<serialization_options<Options>, int>::type = 0>
    constexpr T operator()(Reader & reader, const Options & options, type_tag_t<T> tag = {}) const
        noexcept(noexcept(deserialize_dispatcher.template operator()<T>(reader, options, tag)))
    {
        return deserialize_dispatcher.template operator()<T>(reader, options, tag);
    }
};

/**
 * @brief 全局唯一序列化 CPO 实例
 */
inline constexpr serialize_value_cpo_t serialize_cpo{};

/**
 * @brief 全局唯一反序列化 CPO 实例
 */
inline constexpr deserialize_value_cpo_t deserialize_cpo{};

} // namespace serializer